package co.yixiang.yshop.module.product.service.storeproduct;

import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import co.yixiang.yshop.framework.common.constant.ShopConstants;
import co.yixiang.yshop.framework.common.enums.ShopCommonEnum;
import co.yixiang.yshop.framework.common.exception.ErrorCode;
import co.yixiang.yshop.framework.common.util.json.JsonUtils;
import co.yixiang.yshop.module.product.controller.app.campaigninfo.vo.AppCampaignSkuRespVO;
import co.yixiang.yshop.module.product.controller.app.campaigninfo.vo.CampaignNumberJudgeVO;
import co.yixiang.yshop.module.product.controller.app.coupon.vo.AppCouponDetailRespVO;
import co.yixiang.yshop.module.product.controller.app.product.param.AppStoreProductQueryParam;
import co.yixiang.yshop.module.product.controller.app.product.vo.*;
import co.yixiang.yshop.module.product.convert.storeproduct.StoreProductConvert;
import co.yixiang.yshop.module.product.dal.dataobject.shippingtemplates.ShippingTemplatesDO;
import co.yixiang.yshop.module.product.dal.dataobject.storeproduct.StoreProductDO;
import co.yixiang.yshop.module.product.dal.dataobject.storeproductattrvalue.StoreProductAttrValueDO;
import co.yixiang.yshop.module.product.dal.dataobject.storeproductrelation.StoreProductRelationDO;
import co.yixiang.yshop.module.product.dal.mysql.campaigndetail.CampaignDetailMapper;
import co.yixiang.yshop.module.product.dal.mysql.storeproduct.StoreProductMapper;
import co.yixiang.yshop.module.product.dal.mysql.storeproductattrvalue.StoreProductAttrValueMapper;
import co.yixiang.yshop.module.product.dal.mysql.storeproductrelation.StoreProductRelationMapper;
import co.yixiang.yshop.module.product.dal.redis.RedisKeyConstants;
import co.yixiang.yshop.module.product.enums.ProductConstants;
import co.yixiang.yshop.module.product.enums.campaign.CampaignTypeEnum;
import co.yixiang.yshop.module.product.enums.coupon.CouponTypeEnum;
import co.yixiang.yshop.module.product.enums.product.*;
import co.yixiang.yshop.module.product.service.campaigninfo.AppCampaignInfoService;
import co.yixiang.yshop.module.product.service.category.ProductCategoryService;
import co.yixiang.yshop.module.product.service.productcoupon.AppCouponService;
import co.yixiang.yshop.module.product.service.producttag.ProductTagService;
import co.yixiang.yshop.module.product.service.shippingtemplates.ShippingTemplatesService;
import co.yixiang.yshop.module.product.service.storeproduct.dto.AttrValueDTO;
import co.yixiang.yshop.module.product.service.storeproductassureref.StoreProductAssureRefService;
import co.yixiang.yshop.module.product.service.storeproductattr.AppStoreProductAttrService;
import co.yixiang.yshop.module.product.service.storeproductattrvalue.StoreProductAttrValueService;
import co.yixiang.yshop.module.product.service.storeproductrelation.AppStoreProductRelationService;
import co.yixiang.yshop.module.product.service.storeproductreply.AppStoreProductReplyService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fasterxml.jackson.core.type.TypeReference;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ZSetOperations;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.time.Instant;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import static co.yixiang.yshop.framework.common.enums.OrderInfoEnum.CAMPAIGN_ORDER;
import static co.yixiang.yshop.framework.common.exception.util.ServiceExceptionUtil.exception;
import static co.yixiang.yshop.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
import static co.yixiang.yshop.module.product.enums.ErrorCodeConstants.PRODUCT_STOCK_LESS;
import static co.yixiang.yshop.module.product.enums.ErrorCodeConstants.STORE_PRODUCT_NOT_EXISTS;

/**
 * 商品 AppService 实现类
 *
 * @author yshop
 */
@Slf4j
@Service
@Validated
public class AppStoreProductServiceImpl extends ServiceImpl<StoreProductMapper, StoreProductDO> implements AppStoreProductService {

    @Resource
    private AppStoreProductAttrService appStoreProductAttrService;
    @Resource
    private AppStoreProductRelationService appStoreProductRelationService;
    @Resource
    private AppStoreProductReplyService appStoreProductReplyService;
    @Resource
    private ShippingTemplatesService shippingTemplatesService;
    @Resource
    private StoreProductAttrValueService storeProductAttrValueService;
    @Resource
    private StoreProductAttrValueMapper storeProductAttrValueMapper;
    @Resource
    private StoreProductRelationMapper storeProductRelationMapper;
    @Resource
    private StringRedisTemplate stringRedisTemplate;
    @Resource
    private AppCouponService appCouponService;
    @Resource
    private CampaignDetailMapper campaignDetailMapper;
    @Resource
    private AppCampaignInfoService appCampaignInfoService;
    @Resource
    private ProductTagService productTagService;
    @Resource
    private StoreProductAssureRefService productAssureRefService;
    @Resource
    private ProductCategoryService productCategoryService;

    /**
     * 最近历史搜索的大小
     */
    public static final Integer CURRENT_SEARCH_SIZE = 10;

    /**
     * 商品列表
     *
     * @param page  页码
     * @param limit 条数
     * @param order ProductEnum
     * @return List
     */
    @Override
    public List<AppStoreProductRespVo> getList(int page, int limit, int order) {
        LambdaQueryWrapper<StoreProductDO> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(StoreProductDO::getIsShow, ShopCommonEnum.SHOW.getValue())
                //.eq(YxStoreProduct::getIsDel,ShopCommonEnum.DELETE_0.getValue())
                .orderByDesc(StoreProductDO::getSort);
        wrapper.eq(StoreProductDO::getIsIntegral, 0);
        // order
        switch (ProductEnum.toType(order)) {
            //精品推荐
            case TYPE_1:
                wrapper.eq(StoreProductDO::getIsBest,
                        ShopCommonEnum.YES.getValue());
                break;
            //首发新品
            case TYPE_3:
                wrapper.eq(StoreProductDO::getIsNew,
                        ShopCommonEnum.YES.getValue());
                break;
            // 猜你喜欢
            case TYPE_4:
                wrapper.eq(StoreProductDO::getIsBenefit,
                        ShopCommonEnum.YES.getValue());
                break;
            // 热门榜单
            case TYPE_2:
                wrapper.eq(StoreProductDO::getIsHot,
                        ShopCommonEnum.YES.getValue());
                break;
            default:
        }
        Page<StoreProductDO> pageModel = new Page<>(page, limit);

        IPage<StoreProductDO> pageList = this.baseMapper.selectPage(pageModel, wrapper);

        return StoreProductConvert.INSTANCE.convertList03(pageList.getRecords());
    }


    /**
     * 商品列表
     *
     * @param productQueryParam AppStoreProductQueryParam
     * @return list
     */
    @Override
    public List<AppStoreProductRespVo> getGoodsList(AppStoreProductQueryParam productQueryParam) {

        LambdaQueryWrapper<StoreProductDO> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(StoreProductDO::getIsShow, ShopCommonEnum.SHOW.getValue());

        if (productQueryParam.getIsIntegral() != null) {
            wrapper.eq(StoreProductDO::getIsIntegral, productQueryParam.getIsIntegral());
        }
        //多字段模糊查询分类搜索
        if (StrUtil.isNotBlank(productQueryParam.getSid()) &&
                !ShopConstants.YSHOP_ZERO.equals(productQueryParam.getSid())) {
            List<Long> productIdList = productCategoryService.getProductIdListByCateId(Convert.toLong(productQueryParam.getSid()));
            if(ObjectUtil.isEmpty(productIdList)){
                return new ArrayList<>();
            }
            wrapper.in(CollectionUtils.isNotEmpty(productIdList),StoreProductDO::getId, productIdList);
        }
        // 查询优惠券可用商品
        Long couponId = productQueryParam.getCouponId();
        if (couponId != null && couponId != 0) {
            List<Long> productIdList = appCouponService.getCouponProductList(couponId);
            wrapper.in(CollectionUtils.isNotEmpty(productIdList), StoreProductDO::getId, productIdList);
        }
        //关键字搜索
        if (StrUtil.isNotEmpty(productQueryParam.getKeyword())) {
            wrapper.and(wrapper1 -> {
                wrapper1.or();
                wrapper1.like(StoreProductDO::getStoreName, productQueryParam.getKeyword());
                wrapper1.or();
                wrapper1.like(StoreProductDO::getStoreInfo, productQueryParam.getKeyword());
                wrapper1.or();
                wrapper1.like(StoreProductDO::getKeyword, productQueryParam.getKeyword());
            });
            //缓存用户历史搜索
            Long userId = getLoginUserId();
            addUserSearchHistory(userId, productQueryParam.getKeyword());
            // 缓存搜索记录
            addSearchPopular(productQueryParam.getKeyword());
        }
        //新品搜索
        if (StrUtil.isNotBlank(productQueryParam.getNews()) &&
                !ShopConstants.YSHOP_ZERO.equals(productQueryParam.getNews())) {
            wrapper.eq(StoreProductDO::getIsNew, ShopCommonEnum.NEW.getValue());
        }

        //销量查询
        if (StrUtil.isNotBlank(productQueryParam.getSales()) &&
                !ShopConstants.YSHOP_ZERO.equals(productQueryParam.getSales())) {
            wrapper.orderByDesc(StoreProductDO::getSales);
        }
        if (productQueryParam.getIsDistribution() != null) {
            wrapper.eq(StoreProductDO::getIsDistribution, productQueryParam.getIsDistribution());
        }
        //库存需要大于零
        wrapper.gt(StoreProductDO::getStock, 0);

        Page<StoreProductDO> pageModel = new Page<>(productQueryParam.getPage(), productQueryParam.getLimit());
        IPage<StoreProductDO> pageList = this.baseMapper.selectPage(pageModel, wrapper);
        List<AppStoreProductRespVo> list = StoreProductConvert.INSTANCE.convertList03(pageList.getRecords());
        if (CollectionUtils.isNotEmpty(list)) {
            // 返回活动信息
            List<Long> productIds = list.stream().map(AppStoreProductRespVo::getId).collect(Collectors.toList());
            List<AppCampaignSkuRespVO> campaignDetailDOS = campaignDetailMapper.getCampaignSkus(productIds);
            Map<Long, List<AppCampaignSkuRespVO>> campaignDetailMap =
                    campaignDetailDOS.stream().collect(Collectors.groupingBy(AppCampaignSkuRespVO::getProductId));
            for (AppStoreProductRespVo respVo : list) {
                Long productTagId = respVo.getProductTagId();
                if (productTagId != null) {
                    respVo.setTag(productTagService.findTagById(productTagId));
                }

                List<AppCampaignSkuRespVO> detailDOS = campaignDetailMap.get(respVo.getId());
                if (CollectionUtils.isEmpty(detailDOS)) continue;
                // 默认显示第一个
                AppCampaignSkuRespVO skuRespVO = detailDOS.get(0);
                respVo.setCampaignType(skuRespVO.getType());
                respVo.setSkuId(skuRespVO.getSkuId());
                respVo.setProductAttrUnique(skuRespVO.getProductAttrUnique());
                respVo.setCampaignPrice(skuRespVO.getPrice());
                respVo.setCampaignStock(skuRespVO.getStock());
                respVo.setCampaignTotal(skuRespVO.getTotal());
                respVo.setPerson(skuRespVO.getPerson());
                respVo.setDiscount(skuRespVO.getDiscount());
                respVo.setCampaignState(skuRespVO.getState());
            }
        }
        return list;
    }


    /**
     * 商品详情
     *
     * @param vo
     * @param uid 用户id
     * @return ProductVo
     */
    @Override
    public AppProductVo goodsDetail(AppStoreProductDetailReqVo vo, Long uid) {
        //产品id
        Long id = vo.getProductId();
        LambdaQueryWrapper<StoreProductDO> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(StoreProductDO::getId, id);
        StoreProductDO storeProduct = this.baseMapper.selectOne(wrapper);
        if (ObjectUtil.isNull(storeProduct)) {
            throw exception(STORE_PRODUCT_NOT_EXISTS);
        }

        AppProductVo productVo = new AppProductVo();
        //标签
        Long productTagId = storeProduct.getProductTagId();
        if (productTagId != null) {
            productVo.setTag(productTagService.findTagById(productTagId));
        }
        productVo.setAssureList(productAssureRefService.getAssureListByProductId(id));
        productVo.setIsShow(storeProduct.getIsShow());
        AppStoreProductRespVo storeProductQueryVo = StoreProductConvert.INSTANCE.convert01(storeProduct);

        //设置销量
        storeProductQueryVo.setSales(storeProductQueryVo.getSales() + storeProduct.getFicti());

        if (uid > 0) {
            //设置VIP价格
            //todo
            //收藏
            boolean isCollect = appStoreProductRelationService.isProductRelation(id, uid, RelationCateEnum.COMMON.getValue());
            storeProductQueryVo.setUserCollect(isCollect);
        }
        //总条数
        Long totalCount = appStoreProductReplyService.productReplyCount(id);
        productVo.setReplyCount(totalCount);

        //评价
        AppStoreProductReplyQueryVo storeProductReplyQueryVo = appStoreProductReplyService.getReply(id);
        productVo.setReply(storeProductReplyQueryVo);

        //好评比例
        String replyPer = appStoreProductReplyService.replyPer(id);
        productVo.setReplyChance(replyPer);

        //获取运费模板名称
        String tempName = "";
        if (storeProduct.getPostage().compareTo(BigDecimal.ZERO) == 0 && storeProduct.getTempId() == 0) {
            tempName = ProductConstants.FREE_POSTAGE;
        } else {
            ShippingTemplatesDO shippingTemplates = shippingTemplatesService.getById(storeProduct.getTempId());
            if (ObjectUtil.isNotNull(shippingTemplates)) {
                tempName = shippingTemplates.getName();
            } else {
                tempName = ProductConstants.POSTAGE_TEMP_NOT;
            }

        }
        productVo.setTempName(tempName);
        //设置商品相关信息
        productVo.setStoreInfo(storeProductQueryVo);
        //获取商品sku
        Map<String, Object> returnMap = appStoreProductAttrService.getProductAttrDetail(id);

        //产品规格
        List<AppStoreProductAttrQueryVo> attrList = JsonUtils.parseObject(JsonUtils.toJsonString(returnMap.get("productAttr")),
                new TypeReference<List<AppStoreProductAttrQueryVo>>() {
                });

        //属性集合
        Map<String, AppStoreProductAttrValueVo> attrValueMap = JsonUtils.parseObject(JsonUtils.toJsonString(returnMap.get("productValue")),
                new TypeReference<Map<String, AppStoreProductAttrValueVo>>() {
                });

        if (SpecTypeEnum.SINGLE_SPECS.getValue().equals(storeProduct.getSpecType())) {
            attrValueMap.values().forEach(res -> res.setImage(storeProduct.getImage()));
        }
        String campaignId = null;
        String campaignName = null;
        String campaignRemark = null;
        Integer type = vo.getType();
        Set<String> skuSet = new HashSet<>();
        // 设置营销活动信息
        if (CollectionUtils.isNotEmpty(attrValueMap.values())) {
            // 查询该商品的营销活动
            List<AppCampaignSkuRespVO> campaignSkuRespVOS = campaignDetailMapper.getCampaignSkus(Arrays.asList(id));
            if (CollectionUtils.isNotEmpty(campaignSkuRespVOS)) {
                for (AppCampaignSkuRespVO campaignSkuRespVO : campaignSkuRespVOS) {
                    String sku = campaignSkuRespVO.getSku();
                    AppStoreProductAttrValueVo valueVo = attrValueMap.get(sku);
                    if (ObjectUtil.isNull(valueVo)) continue;
                    valueVo.setCampaignId(campaignSkuRespVO.getId());
                    valueVo.setCampaignDetailId(campaignSkuRespVO.getDetailId());
                    valueVo.setCampaignStock(campaignSkuRespVO.getStock());
                    valueVo.setCampaignPrice(campaignSkuRespVO.getPrice());
                    valueVo.setIntegral(campaignSkuRespVO.getIntegral());
                    valueVo.setCampaignStock(campaignSkuRespVO.getStock());
                    valueVo.setCampaignTotal(campaignSkuRespVO.getTotal());
                    valueVo.setCampaignType(campaignSkuRespVO.getType());
                    valueVo.setDiscount(campaignSkuRespVO.getDiscount());
                    valueVo.setPerson(campaignSkuRespVO.getPerson());
                    valueVo.setStartTime(campaignSkuRespVO.getStartTime());
                    valueVo.setEndTime(campaignSkuRespVO.getEndTime());
                    valueVo.setCampaignState(campaignSkuRespVO.getState());

                    //积分商城的查询中过滤没有配置的规格
                    if (campaignSkuRespVO.getId() == null && campaignSkuRespVO.getType() == null
                            && CampaignTypeEnum.INTEGRAL.getValue().equals(type)) {
                        attrValueMap.remove(sku);
                        continue;
                    }
                    if (campaignId == null) {
                        campaignId = campaignSkuRespVO.getCampaignId();
                    }
                    if (campaignName == null) {
                        campaignName = campaignSkuRespVO.getCampaignName();
                    }
                    if (campaignRemark == null) {
                        campaignRemark = campaignSkuRespVO.getCampaignRemark();
                    }
                    //规格集合
                    skuSet.addAll(StrUtil.split(sku, ","));
                }
            }
        }
        productVo.setProductValue(attrValueMap);
        //活动信息
        productVo.setCampaignId(campaignId);
        productVo.setCampaignName(campaignName);
        productVo.setCampaignRemark(campaignRemark);

        //过滤积分商城中没有配置的规格
        if (campaignId != null && CampaignTypeEnum.INTEGRAL.getValue().equals(type)) {
            List<AppStoreProductAttrQueryVo> collect = attrList.stream().peek(item -> {
                List<AttrValueDTO> attrValue = item.getAttrValue().stream().filter(x -> skuSet.contains(x.getAttr())).collect(Collectors.toList());
                item.setAttrValue(attrValue);

                List<String> attrValueArr = item.getAttrValueArr().stream().filter(skuSet::contains).collect(Collectors.toList());
                item.setAttrValueArr(attrValueArr);

                item.setAttrValues(String.join(",", attrValueArr));
            }).collect(Collectors.toList());
            productVo.setProductAttr(collect);
        } else {
            productVo.setProductAttr(attrList);
        }

        //添加足迹,先删除之前的，更新时间
        LambdaQueryWrapper<StoreProductRelationDO> productDOLambdaQueryWrapper = new LambdaQueryWrapper<>();
        storeProductRelationMapper.delete(
                productDOLambdaQueryWrapper.eq(StoreProductRelationDO::getProductId, id)
                        .eq(StoreProductRelationDO::getUid, uid)
                        .eq(StoreProductRelationDO::getType, RelationEnum.FOOT.getValue()));
        StoreProductRelationDO storeProductRelationDO = StoreProductRelationDO.builder()
                .productId(id)
                .uid(uid)
                .category("common")
                .type(RelationEnum.FOOT.getValue())
                .build();
        storeProductRelationMapper.insert(storeProductRelationDO);

        // 设置优惠券信息
        List<AppCouponDetailRespVO> couponDetailList = appCouponService.receiveList(id, uid);
        if (CollectionUtils.isNotEmpty(couponDetailList)) {
            AppCouponDetailRespVO couponDetail = couponDetailList.get(0);
            if (CouponTypeEnum.FULL_REDUCTION.getValue().equals(couponDetail.getCouponType())) {
                productVo.setCouponSplicing("满" + couponDetail.getThreshold() + "元减" + couponDetail.getCouponValue());
            } else {
                productVo.setCouponSplicing("满" + couponDetail.getThreshold() + "元" + couponDetail.getDiscount() + "折");
            }

        }
        return productVo;
    }


    /**
     * 返回商品库存
     *
     * @param productId 商品id
     * @param unique    sku唯一值
     * @return int
     */
    @Override
    public int getProductStock(Long productId, String unique, Integer type, int cartNum) {
        StoreProductAttrValueDO storeProductAttrValue = storeProductAttrValueService
                .getOne(Wrappers.<StoreProductAttrValueDO>lambdaQuery()
                        .eq(StoreProductAttrValueDO::getUnique, unique)
                        .eq(StoreProductAttrValueDO::getProductId, productId));

        if (storeProductAttrValue == null) {
            throw exception(new ErrorCode(202502210,"该商品属性有变动请重新下单！"));
        }
        // 活动商品购买数量限制
        if (Objects.equals(CAMPAIGN_ORDER.getValue(), type)) {
            return appCampaignInfoService.numberJudge(new CampaignNumberJudgeVO(unique, null, cartNum));
        }
//        if (ProductTypeEnum.PINK.getValue().equals(type))
//            return storeProductAttrValue.getPinkStock();
//        } else if (ProductTypeEnum.SECKILL.getValue().equals(type)) {
//            return storeProductAttrValue.getSeckillStock();
////        }
        return storeProductAttrValue.getStock();

    }

    /**
     * 获取单个商品
     *
     * @param id 商品id
     * @return YxStoreProductQueryVo
     */
    @Override
    public AppStoreProductRespVo getStoreProductById(Long id) {
        return StoreProductConvert.INSTANCE.convert01(this.baseMapper.selectById(id));
    }

    @Override
    public List<AppStoreProductRespVo> getStoreProductByIds(List<Long> ids) {
        return StoreProductConvert.INSTANCE.convertList03(this.baseMapper.selectBatchIds(ids));
    }


    /**
     * 减少库存与增加销量
     *
     * @param num       数量
     * @param productId 商品id
     * @param unique    sku
     */
    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public void decProductStock(int num, Long productId, String unique, Long activityId, String type) {


        int res = storeProductAttrValueMapper.decStockIncSales(num, productId, unique);

        if (res == 0) {
            throw exception(PRODUCT_STOCK_LESS);
        }

        int product = this.baseMapper.decStockIncSales(num, productId);
        if (product == 0) {
            throw exception(PRODUCT_STOCK_LESS);
        }


    }

    @Override
    public void incSales(Integer num, Long productId) {
        this.baseMapper.incSales(num, productId);
    }


    /**
     * 增加库存 减少销量
     *
     * @param num       数量
     * @param productId 商品id
     * @param unique    sku唯一值
     * @param type      回退类型
     */
    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public void incProductStock(Integer num, Long productId, String unique, Integer type) {
        log.info("回退库存类型：{}", type);
        if (StockBackTypeEnum.NORMAL.getValue().equals(type)) {
            //处理属性sku
            if (StrUtil.isNotEmpty(unique)) {
                storeProductAttrValueMapper.incStockDecSales(num, productId, unique);
            }
            //更新商品
            this.baseMapper.incStockDecSales(num, productId);
        } else {
            // 增加活动库存
            appCampaignInfoService.backStock(unique, num);
            //更新商品
            this.baseMapper.incSales(-num, productId);
        }
    }

    private void addUserSearchHistory(Long userId, String keyWord) {
        String key = RedisKeyConstants.YSHOP_USER_SEARCH_HISTORY_KEY.formatKey(userId);
        //历史搜索记录保持30天，30天不登录查询则自动过期
        stringRedisTemplate.expire(key, 30, TimeUnit.DAYS);

        ZSetOperations<String, String> zSet = stringRedisTemplate.opsForZSet();
        //由于zset 的集合特性当插入已经存在的 v 值 (搜索记录) 时只会更新score 值，
        zSet.add(key, keyWord, Instant.now().getEpochSecond());

        //只得到当前用户的最近搜索记录,注意这里必须保证set集合的顺序
        Set<String> userRecentSearches = listRecentSearch(userId);

        if (userRecentSearches.size() > CURRENT_SEARCH_SIZE) {
            //获取到最开始浏览的第一条
            String firstSearch = userRecentSearches.stream().reduce((first, second) -> second).orElse(null);
            //删除最开始浏览的第一条
            zSet.remove(key, firstSearch);
        }
    }


    /**
     * 历史最近搜索列表
     *
     * @return 历史搜索列表
     */
    @Override
    public Set<String> listRecentSearch(Long userId) {
        String key = RedisKeyConstants.YSHOP_USER_SEARCH_HISTORY_KEY.formatKey(userId);
        Set<ZSetOperations.TypedTuple<String>> typedTuples = stringRedisTemplate.opsForZSet().reverseRangeWithScores(key, 0, -1);
        return Optional.ofNullable(typedTuples)
                .map(tuples -> tuples.stream()
                        .map(ZSetOperations.TypedTuple::getValue)
                        .filter(Objects::nonNull)
                        .limit(20)
                        .collect(Collectors.collectingAndThen(
                                Collectors.toCollection(LinkedHashSet::new), LinkedHashSet::new)))
                .orElseGet(LinkedHashSet::new);
    }


    @Override
    public void removeSearchHistoryAll(Long userId) {
        stringRedisTemplate.delete(RedisKeyConstants.YSHOP_USER_SEARCH_HISTORY_KEY.formatKey(userId));
    }

    @Override
    public Set<String> searchPopular(Long start, Long end) {
        String key = RedisKeyConstants.YSHOP_POPULAR_SEARCH_RECORDS_KEY.formatKey();
        return stringRedisTemplate.opsForZSet().reverseRange(key, start, end);
    }

    /**
     * 缓存搜索记录
     *
     * @param keyWord 搜索关键字
     */
    private void addSearchPopular(String keyWord) {
        String key = RedisKeyConstants.YSHOP_POPULAR_SEARCH_RECORDS_KEY.formatKey();
        stringRedisTemplate.opsForZSet().incrementScore(key, keyWord, 1);
    }

}
